/*
 * File Name: fdtc.h
 *
 * Copyright 2024-, lishanwen (1477153217@qq.com)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */


#ifndef __FDTC_H__
#define __FDTC_H__


#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <stdint.h>
#include <limits.h>
#include <inttypes.h>


/**
 * @brief Get the offset of internal members of the structure
 * 
 * @struct_t: structure typedef 
 * @member: member in structure
 * 
 * @return offset of member in the structure
*/
#define   fdt_offsetof(struct_t, member)      \
               ((size_t)&((struct_t*)0)->member)


/**
 * @brief Get the address of the structure instance.
 *
 * @ptr: address of the structure member.
 * @type: type of the structure.
 * @member: member name of the ptr in structure.
 *   
 * @return pointer to address of structure 
 */
#define container_of(ptr, type, member)      ({ \
               (type *)((char *)ptr - fdt_offsetof(type, member)); })


/**
 * @prev: previous node of the list.
 * @next: next node of the list.
 */
typedef struct list_node {
	struct list_node *prev;
	struct list_node *next;

}list_node_t;


#define LIST_HEAD(name) \
	list_node_t name = {.prev = &(name), .next = &(name)}


/**
 * @brief foreach the list.
 *
 * @pos: the &struct list_head to use as a loop cursor.
 * @list_head: the head for your list.
 * 
 * @return none
 */
#define list_for_each(pos, list_head) \
	for (pos = (list_head)->next; pos != (list_head); pos = pos->next)


/**
 * @brief Return the next entry of specific node.
 *
 * @entry: specific entry.
 *
 * @return entry_type: next entry of specific entry.
 */
#define list_next_entry(entry, entry_type, list_node_member) \
	container_of(entry->list_node_member.next, entry_type, list_node_member)


/**
 * @brief Return the previous entry of specific node.
 *
 * @entry: specific entry.
 *
 * @return entry_type: previous entry of specific entry.
 */
#define list_prev_entry(entry, entry_type, list_node_member) \
	container_of(entry->list_node_member.prev, entry_type, list_node_member)


/**
 * @brief foreach the list inserted in a structure.
 *
 * @pos: the &struct list_head to use as a loop cursor.
 * @list_head: the head for your list.
 * @entry_type: type of the struct.
 * @list_node_member: member name of the list_node in structure.
 *
 * @return none
 */
#define list_for_each_entry(pos, list_head, entry_type, list_node_member) \
	for (pos = container_of((list_head)->next, entry_type, list_node_member); \
	     &pos->list_node_member != (list_head); \
	     pos = container_of(pos->list_node_member.next, entry_type, list_node_member))


/**
 * @brief inititialize a list.
 *
 * @node: inserted node.
 *
 * @return none
 */
static inline void list_init(list_node_t *node) 
{
    node->next = node;
    node->prev = node;
}


/**
 * @brief Add a node to the list tail.
 *
 * @head: head node of the list.
 * @node: inserted node.
 * 
 * @return none
 */
static inline void list_add_node_at_tail(list_node_t *head, list_node_t *node)
{
    list_node_t *tail = head->prev;

    node->prev = tail;
    node->next = head;
    tail->next = node;
    head->prev = node;
}


/**
 * @brief Replace a node in the list.
 *
 * @old: old node.
 * @new: new node.
 * 
 * @return none
 */
static inline void list_replace_node(list_node_t *old, list_node_t *new)
{
    new->next = old->next;
    new->prev = old->prev;
    new->next->prev = new;
    new->prev->next = new;
}


/**
 * @brief Add a node to the list front.
 *
 * @head: head node of the list.
 * @node: inserted node.
 * 
 * @return none
 */
static inline void list_add_node_at_front(list_node_t *head, list_node_t *node)
{
    list_node_t *front = head->next;

    node->prev = head;
    node->next = front;
    front->prev = node;
    head->next = node;
}


/**
 * @brief Delete a tail node from the list.
 *
 * @head: head node of the list.
 * 
 * @return none
 */
static inline void list_del_tail_node(list_node_t *head)
{
    list_node_t *tail_prev = head->prev->prev;

    tail_prev->next = head;
    head->prev = tail_prev;
}


/**
 * @brief  Delete a front node from the list.
 *
 * @head: head node of the list.
 * 
 * @return none
 */
static inline void list_del_front_node(list_node_t *head)
{
    list_node_t *front_next = head->next->next;

    front_next->prev = head;
    head->next = front_next;
}


/**
 * @brief  Delete a node from the list.
 *
 * @node: the node of the list.
 * 
 * @return none
 */
static inline void list_del_node(list_node_t *node)
{
    node->prev->next = node->next;
    node->next->prev = node->prev;
}


/**
 * @brief Determine whether the list is empty.
 *
 * @head: head node of the list.
 * 
 * @return  bool: is empty.
 */
static inline bool list_is_empty(list_node_t *head)
{
    return head->next == head;
}


/**
 * @brief Return the next node of specific node.
 *
 * @node: specific node.
 *
 * @return list_node*: next node of specific node.
 */
static inline list_node_t* list_next_node(list_node_t *node)
{
    return node->next;
}


/**
 * @brief Return the previous node of specific node.
 *
 * @node: specific node.
 * 
 * @return list_node*: previous node of specific node.
 */
static inline list_node_t* list_prev_node(list_node_t *node)
{
    return node->prev;
}


/**
 * @brief Property type.
 * @FDT_PROP_INT  : integer type.
 * @FDT_PROP_STRING: string type.
 */
typedef enum {
    FDT_PROP_STRING = 0,
	FDT_PROP_INT,
	FDT_PROP_ARRAY,
	FDT_PROP_INVALID = 255,
	
}fdt_prop_type_t;


#define FDT_PROP_ARRAY_MAX   256
#define FDT_MACRO_LEN_MAX    512
#define FDT_MACRO_CACHE_SIZE 4096

/** 
 * @brief Property node.
 * @name: property name.
 * @type: property type.
 * @union: property value.
 * @node: next node.
 */
typedef struct fdt_prop {
    list_node_t node;
    char* name;
    fdt_prop_type_t type;

	char* str_value;
	uint64_t int_value;
	uint64_t array[FDT_PROP_ARRAY_MAX];
	uint64_t array_len;
	uint64_t array_cell_size;

}fdt_prop_t;


/**
 * @brief fdt node struct.
 * @parent: parent node.
 * @entry: next node.
 * @name: node name.
 * @prop: property node.
 */
typedef struct fdt_node {
    struct fdt_node *parent;
    list_node_t entry;
    list_node_t child;
    char *name;
    list_node_t prop;

}fdt_node_t;


/**
 * @brief macro node struct.
 * @entry: next node.
 * @name: macro name.
 * @value: macro value.
 */
typedef struct fdt_macro {
    list_node_t entry;
    char name[FDT_MACRO_LEN_MAX];
    char value[FDT_MACRO_LEN_MAX];

}fdt_macro_t;


/**
 * @brief macro cache struct.
 * @ref: reference count.
 * @macro: macro node.
 */
typedef struct macro_cache {
    size_t ref;
    fdt_macro_t *macro;

}macro_cache_t;


/**
 * @brief macro cache head struct.
 * @cache: macro cache.
 * @count: macro count.
 */
typedef struct macro_cache_head {
    macro_cache_t cache[FDT_MACRO_CACHE_SIZE];
    int count;

}macro_cache_head_t;


/**
 * @brief FDT magic number. meaning "fdt"
 */
#define FDT_MAGIC               0x746466

/**
 * @brief FDT version. year, month, day
 */
#define FDT_VERSION             0x250421

/**
 * @brief FDT copyright
 */
#define FDT_COPYRIGHT           "Copyright (C) 2024-2030 li-shanwen(1477153217@qq.com), Apache License 2.0\n"


#define FDT_LOG_ERROR(...)      printf("[ERROR]"__VA_ARGS__)
#define FDT_LOG_INFO(...)       printf("[INFO]"__VA_ARGS__)


/**
 * @brief main function
 * 
 * @return int, 0: success, -1: failed
 */
int libfdt_main(int argc, char *argv[]);


#endif // ! __FDTC_H__
